﻿using System;
using System.Drawing;
using System.Windows.Forms;

namespace Quazistax.Win
{
    public enum DragCursorHorizontalPosition { Left, Center, Right };
    public enum DragCursorVerticalPosition { Top, Center, Bottom };

    public class QQDragImageForm : Form
    {
        /// <summary>
        /// Required designer variable.
        /// </summary>
        private System.ComponentModel.IContainer components = null;

        /// <summary>
        /// Clean up any resources being used.
        /// </summary>
        /// <param name="disposing">true if managed resources should be disposed; otherwise, false.</param>
        protected override void Dispose(bool disposing)
        {
            if (disposing && (components != null))
            {
                components.Dispose();
            }
            base.Dispose(disposing);
        }

        #region Windows Form Designer generated code

        /// <summary>
        /// Required method for Designer support - do not modify
        /// the contents of this method with the code editor.
        /// </summary>
        private void InitializeComponent()
        {
            System.ComponentModel.ComponentResourceManager resources = new System.ComponentModel.ComponentResourceManager(typeof(QQDragImageForm));
            this.SuspendLayout();
            // 
            // QQDragImageForm
            // 
            this.BackColor = System.Drawing.Color.White;
            //this.BackgroundImage = ((System.Drawing.Image)(resources.GetObject("$this.BackgroundImage")));            
            this.ClientSize = new System.Drawing.Size(385, 77);
            this.ControlBox = false;
            this.FormBorderStyle = System.Windows.Forms.FormBorderStyle.None;
            this.Name = "QQDragImageForm";
            this.Opacity = 0.5;
            this.ShowIcon = false;
            this.ShowInTaskbar = false;
            this.StartPosition = System.Windows.Forms.FormStartPosition.Manual;
            this.TopMost = true;
            this.TransparencyKey = System.Drawing.Color.Transparent;
            this.VisibleChanged += new System.EventHandler(this.QQDragImageForm_VisibleChanged);
            this.ResumeLayout(false);

        }

        #endregion

        public QQDragImageForm()
        {
            SetStyle(ControlStyles.SupportsTransparentBackColor, true);
            SetStyle(ControlStyles.OptimizedDoubleBuffer, false);
            SetStyle(ControlStyles.Selectable, false);
            InitializeComponent();
            //to resize the form to match initial image
            this.BackgroundImage = this.BackgroundImage;
        }

        protected int RemoveStyles = 0;
        protected int AddStyles = 0;
        protected int RemoveExStyles = 0;
        protected int AddExStyles = 0
            | 0x00000020 // WS_EX_TRANSPARENT // to pass through mouse events
            | 0x00000080 // WS_EX_TOOLWINDOW // so it doesn't show in alt+tab window list
            ;

        protected override CreateParams CreateParams
        {
            get
            {
                CreateParams p = base.CreateParams;
                p.Style &= ~RemoveStyles;
                p.Style |= AddStyles;

                p.ExStyle &= ~RemoveExStyles;
                p.ExStyle |= AddExStyles;
                return p;
            }
        }

        private Point _ImageOffset;
        // image position relative to cursor
        protected Point ImageOffset
        {
            get { return _ImageOffset; }
            set
            {
                _ImageOffset = value;
                SyncLocationWithMouse();
            }
        }

        public override Image BackgroundImage
        {
            get { return base.BackgroundImage; }
            set
            {
                if (value != null)
                    this.Size = value.Size;
                else
                    this.Size = new Size();

                base.BackgroundImage = value;
            }
        }

        #region Show
        public void Show(Image image)
        {
            Show(image, Color.Transparent);
        }

        public void Show(Image image, Color transparentColor)
        {
            this.BackColor = transparentColor;
            this.TransparencyKey = transparentColor;

            if (transparentColor != Color.Transparent)
            {
                Bitmap bmp = (Bitmap)image;
                bmp.MakeTransparent(transparentColor);
                this.BackgroundImage = bmp;
            }
            else
                this.BackgroundImage = image;

            //reduces flicker if we first show form off screen and then move it to target location
            this.Location = new Point(-10000, -10000);

            this.Show();
        }

        //reduces flicker if we first show form off screen and then move it to target location
        private void QQDragImageForm_VisibleChanged(object sender, EventArgs e)
        {
            if (this.Visible)
                if (Location.X == -10000 || Location.Y == -10000)
                {
                    WindowsFormsSynchronizationContext sc = System.Threading.SynchronizationContext.Current as WindowsFormsSynchronizationContext;
                    if (sc != null)
                        sc.Post(delegate(object state) { SyncLocationWithMouse(); }, null);
                    else
                        SyncLocationWithMouse();
                }
        }

        public void Show(Image image, DragCursorHorizontalPosition hpos, DragCursorVerticalPosition vpos)
        {
            Show(image, Color.Transparent, hpos, vpos);
        }

        public void Show(Image image, Color transparentColor, DragCursorHorizontalPosition hpos, DragCursorVerticalPosition vpos)
        {
            int x = 0, y = 0;
            if (hpos == DragCursorHorizontalPosition.Center)
                x = -image.Width / 2;
            else if (hpos == DragCursorHorizontalPosition.Right)
                x = -image.Width;

            if (vpos == DragCursorVerticalPosition.Center)
                y = -image.Height / 2;
            else if (vpos == DragCursorVerticalPosition.Bottom)
                y = -image.Height;

            this.ImageOffset = new Point(x, y);

            Show(image, transparentColor);
        }

        public void Show(Image image, Color transparentColor, int hCustomCursorPos, int vCustomCursorPos)
        {
            this.ImageOffset = new Point(-hCustomCursorPos, -vCustomCursorPos);
            Show(image, transparentColor);
        }

        public void Show(Image image, int hCustomCursorPos, int vCustomCursorPos)
        {
            this.ImageOffset = new Point(-hCustomCursorPos, -vCustomCursorPos);
            Show(image, Color.Transparent);
        }
        #endregion

        public void SyncLocationWithMouse(Point mousePosition)
        {
            Point pos = mousePosition;
            pos.Offset(_ImageOffset.X, _ImageOffset.Y);
            this.Location = pos;
            this.BringToFront(); //to make sure other top level windows dont obscure this one
        }
        public void SyncLocationWithMouse()
        {
            SyncLocationWithMouse(Form.MousePosition);
        }


        public static int CalculateCursorHPos(Image image, DragCursorHorizontalPosition hpos, int cursorHOffset)
        {
            int x = cursorHOffset;
            if (hpos == DragCursorHorizontalPosition.Center)
                x += image.Width / 2;
            else if (hpos == DragCursorHorizontalPosition.Right)
                x += image.Width;

            return x;
        }

        public static int CalculateCursorVPos(Image image, DragCursorVerticalPosition vpos, int cursorVOffset)
        {
            int y = cursorVOffset;
            if (vpos == DragCursorVerticalPosition.Center)
                y += image.Height / 2;
            else if (vpos == DragCursorVerticalPosition.Bottom)
                y += image.Height;

            return y;
        }



    }
}
